<?php

declare(strict_types=1);

namespace PluginInstaller;


use Composer\IO\IOInterface;
use Composer\Json\JsonFile;
use Composer\Script\Event;

class PluginInstaller
{
    public static function postPackageInstall(Event $event): void
    {
        $io = $event->getIO();

        $rootPath = dirname(__DIR__) . DIRECTORY_SEPARATOR; // 上一级目录，通常是项目根目录
        $installerPath = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'installer'; // 上一级目录，通常是项目根目录
        $vendorPath = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'vendor'; // 上一级目录，通常是项目根目录
        $lockPath = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'composer.lock'; // 上一级目录，通常是项目根目录
        $gitPath = dirname(__DIR__) . DIRECTORY_SEPARATOR . '.git'; // 上一级目录，通常是项目根目录
        $ideaPath = dirname(__DIR__) . DIRECTORY_SEPARATOR . '.idea'; // 上一级目录，通常是项目根目录
        // 尝试执行整个安装流程
        try {
            $pluginName = self::askForPluginName($io);
            //判断名字是否存在，然后生成下一步默认的空间命名

            $vendorNamespace = self::askForVendorNamespace($io,$pluginName);
            $pluginName = 'plugins'. DIRECTORY_SEPARATOR . $pluginName;
            $description = self::askForDescription($io);

            // 定义目录结构数组
            $directories = [
                "manifest",
                "src/Constants",
                "src/Exception",
                "src/QueueService",
                "src/Listener",
                "src/Middleware",
                "src/Action",
                "src/Logic",
                "src/Service",         
                "src/Internal",      
                "src/Internal/Action",
                "src/Internal/Logic",
                "src/Internal/Service",
                "src/Internal/Service/Model",
                "src/Internal/Service/Interface",
            ];

            // 创建目录结构
            self::createPluginDirectories($rootPath, $directories);

            // 创建 composer.json 文件
            self::modifyComposerJson($io,$rootPath, $pluginName, $description,$vendorNamespace);
            $io->write("你已经成功创建插件：{$pluginName}，成功后请在根目录下使用 composer require {$pluginName} 进行安装");
            $io->write("准备清理不需要的文件和文件夹...");
            // 调用清理方法，删除不需要的文件和文件夹
            $io->write("准备清理install文件夹...");
            self::deleteDirectory($installerPath);
            $io->write("准备清理vendor文件夹...");
            self::deleteDirectory($vendorPath);
            $io->write("准备清理composer.lock文件...");
            self::deleteDirectory($lockPath);
            // todo 后期修复除src外都删除
            $io->write("准备清理.git文件...");
            self::deleteDirectory($gitPath);
            $io->write("准备清理.idea文件...");
            self::deleteDirectory($ideaPath);
            // 输出结果信息
            $io->write("<info>Plugin `{$pluginName}` directory structure and composer.json have been created successfully.</info>");
        } catch (\Exception $e) {
            // 异常处理，给予用户清晰的错误信息
            $io->writeError('<error>An error occurred: ' . $e->getMessage() . '</error>');
        }
    }

    private static function askForVendorNamespace(IOInterface $io,string $pluginName): string
    {
        return self::ask(
            $io,
            "请输入插件的命名空间 (默认： Plugins\\".ucfirst($pluginName)."): ",
            "Plugins\\".ucfirst($pluginName),
            function ($input) {
                if (!preg_match('/^[a-zA-Z0-9\\\\]+$/', $input)) {
                    throw new \RuntimeException('The namespace contains invalid characters.');
                }
                return $input;
            }
        );
    }

    private static function askForPluginName(IOInterface $io): string
    {
        return self::ask(
            $io,
            '请输入插件的名称 (默认："demo"): ',
            'demo',
            function ($input) {
                if (!preg_match('/^[a-z0-9\-]+$/', $input)) {
                    throw new \RuntimeException('The plugin name format is invalid.');
                }
                return $input;
            }
        );
    }

    private static function askForDescription(IOInterface $io): string
    {
        return self::ask($io, '请输入插件的介绍: ', 'A custom plugin for my project.');
    }

    private static function askForRootPath(IOInterface $io): string
    {
        return self::ask(
            $io,
            'Enter the root directory for the plugin (e.g., "src/"): ',
            'src/',
            function ($input) {
                // Validate path ends with a slash, and adjust according to OS
                $slash = DIRECTORY_SEPARATOR;
                $input = rtrim($input, '/\\') . $slash; // 移除尾部斜杠后再统一添加
                if (preg_match('#[^a-zA-Z0-9_\-/\\\\]#', $input)) {
                    throw new \RuntimeException('The root directory contains invalid characters.');
                }
                return $input; // 确保返回更新后的路径
            }
        );
    }


    private static function createPluginDirectories(string $rootPath, array $directories): void
    {
        foreach ($directories as $directory) {
            $dirPath = $rootPath . $directory;
            if (!is_dir($dirPath)) {
                if (!mkdir($dirPath, 0755, true) && !is_dir($dirPath)) {
                    throw new \RuntimeException(sprintf('Directory "%s" was not created', $dirPath));
                }
            }
        }
    }

    private static function createComposerJsonFile(string $rootPath, string $pluginName, string $description): void
    {
        $composerJsonContent = json_encode([
            "name" => $pluginName,
            "description" => $description,
            "type" => "library",
            "autoload" => [
                "psr-4" => [str_replace('/', '\\', $pluginName) . '\\' => $rootPath]
            ],
            "require" => new \stdClass(),
        ], JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);

        if (false === file_put_contents($rootPath . "composer.json", $composerJsonContent)) {
            throw new \RuntimeException('Failed to write composer.json file.');
        }
    }

    private static function ask(IOInterface $io, string $question, $default = null, callable $validator = null): string
    {
        do {
            $input = $io->ask($question, $default);

            $isValid = true; // 默认假设输入是有效的
            if ($validator) {
                try {
                    $input = $validator($input);
                } catch (\RuntimeException $e) {
                    // 如果验证器抛出异常，输入无效
                    $io->writeError('<error>' . $e->getMessage() . '</error>');
                    $isValid = false;
                }
            }

            // 如果输入有效，跳出循环并返回输入
            if ($isValid) {
                return $input;
            }
        } while (true);
    }
    private static function cleanUp(): void
    {
        // 定义当前目录下要删除的文件和文件夹
        $itemsToDelete = [
            'src',
            'composer.json',
            'composer.lock',
            'vendor',
        ];

        foreach ($itemsToDelete as $item) {
            if (is_dir($item)) {
                self::deleteDirectory($item);
            } elseif (file_exists($item)) {
                unlink($item);
            }
        }
    }

    private static function deleteDirectory(string $dir): void
    {
        if (!is_dir($dir)) {
            if (file_exists($dir)) {
                unlink($dir);
                return;
            }
        }

        $objects = scandir($dir);
        foreach ($objects as $object) {
            if ($object !== "." && $object !== "..") {
                if (is_dir($dir . DIRECTORY_SEPARATOR . $object) && !is_link($dir . '/' . $object)) {
                    self::deleteDirectory($dir . DIRECTORY_SEPARATOR . $object);
                } else {
                    unlink($dir . DIRECTORY_SEPARATOR . $object);
                }
            }
        }
        rmdir($dir);
    }
    private static function modifyComposerJson(IOInterface $io,string $rootPath, string $pluginName, string $description,string $vendorNamespace): void
    {

        $content = file_get_contents(__DIR__ . '/resources/ConfigProvider.stub');
        $content = str_replace('%NAMESPACE%', $vendorNamespace, $content);
        file_put_contents(__DIR__ . '/../src/ConfigProvider.php', $content);        
        $composerJsonFile = new JsonFile($rootPath . 'composer.json');

        try {
            $composerJsonContent = [
                "name" => $pluginName,
                "description" => $description,
                "license" => "GPL-3.0",
                "type" => "library",
                "autoload" => [
                    "psr-4" => [str_replace('/', '\\', $vendorNamespace) . '\\' => "src/"]
                ],
                "require" => new \stdClass(),
                "extra"=> [
                    "hyperf"=> [
                        "config"=> str_replace('/', '\\', $vendorNamespace) . '\\' . 'ConfigProvider'
                    ],
                    "branch-alias"=> [
                        "dev-master"=> "1.0-dev",
                        "dev-main"=> "1.0-dev"
                    ],
                    "hooks"=> [
                        "pre-commit"=> [
                            "echo committing as $(git config user.name)",
                            "vendor/bin/php-cs-fixer fix .",
                            "git add .",
                            "composer test"
                        ]
                    ]
                ],
                "scripts" => [
                    "cs-fix" =>"php-cs-fixer fix $1",
                    "test" =>"phpunit --colors=always"
                ]
            ];

            // 写回到composer.json文件中
            $composerJsonFile->write($composerJsonContent);
        } catch (\Exception $e) {
            // 处理异常，例如输出错误信息
            $io->writeError('<error>Failed to read or write composer.json: ' . $e->getMessage() . '</error>');
            // 也可以选择重抛异常或者执行其他错误处理逻辑
            // throw $e;
        }

    }


}
